package webhandler

import (
	"errors"
	"fmt"

	"github.com/gogo/protobuf/jsonpb"
	jsoniter "github.com/json-iterator/go"
	"github.com/kataras/iris/v12"
	"github.com/micro/go-micro/v2/client"

	//"go.uber.org/zap"
	"net/http"
	"strconv"
	"strings"
	"time"

	//wrapperTrace "gitee.com/tgodfather/go-plugins/wrapper/trace/opentracing"
	"hmsDemo/hms.api/config"
	"sync"

	grpc "gitee.com/tgodfather/go-plugins/client/grpc"
	log "gitee.com/tgodfather/misc/logger"

	"go.uber.org/zap"
)

var (
	ErrNotImplement = errors.New("Method Not Implement\n")
	ErrNotFound     = errors.New("Method Not Found\n")

	ErrorCode_Common         = 20000
	ErrorCode_MethodNotFound = 20405

	//用于 json 转 pb message
	//json = jsoniter.ConfigCompatibleWithStandardLibrary
	//JsonToPb = jsoniter.Config{
	//	UseNumber:              true,
	//	EscapeHTML:             true,
	//	SortMapKeys:            false,
	//	ValidateJsonRawMessage: true,
	//}.Froze()
	JsonToPb = NewWebUnmarshler()
	//用于 pb message 转 json， 输出json时默认忽略 omitempty
	PbToJson = &jsonpb.Marshaler{
		EnumsAsInts:  true,
		EmitDefaults: true,
		//OrigName:true,
	}
	//WebCenter
	once  sync.Once
	defWh *WebCenter = nil

	//callOpt []client.CallOption
)

type WebUnmarshler struct {
	jsonToPb jsoniter.API
}

func NewWebUnmarshler() *WebUnmarshler {
	wu := new(WebUnmarshler)
	wu.jsonToPb = jsoniter.Config{
		UseNumber:              true,
		EscapeHTML:             true,
		SortMapKeys:            false,
		ValidateJsonRawMessage: true,
	}.Froze()
	return wu
}

func (m *WebUnmarshler) Unmarshal(data []byte, outPtr interface{}) error {
	//log.Debug("Got Request", zap.ByteString("body", data))
	return m.jsonToPb.Unmarshal(data, outPtr)
}

//sync.once

func GetWebCenter() *WebCenter {
	once.Do(func() {
		defWh = newWebHandler()
	})
	return defWh
}

////根据配置， 添加路由规则, 设置完成返回http.Handler
//func SetHttpRoute(httpMethod string , httpPath string, service string) {
//
//	wh := GetWebCenter()
//	wh.SetHttpRoute(httpMethod , httpPath, service)
//	//return defWh.BuildHandler(cfg)
//}

//func GetHttpHandler() http.Handler{
//	wh := GetWebCenter()
//
//	return wh.GetHttpHandler()
//}

//Web 插件初始化函数
type FuncWebPluginInit func(*WebCenter) error

//注册Web插件初始化 ,  由WebCenter执行 Web插件的初始化设置
func RegisterWebPlugin(pluginName string, f FuncWebPluginInit) {
	wh := GetWebCenter()
	wh.RegisterWebPlugin(pluginName, f)
}

////注册函数
//func RegisterWebHandler(serviceName  string, h iris.Handler){
//
//	wh := GetWebCenter()
//
//	wh.RegisterWebHandler(serviceName, h)
//}

type WebCenter struct {
	app       *iris.Application
	appBuild  bool //表示 app 是否已经build, 如果已经build则不再build
	cfg       *config.ServiceConfig
	mapPlugin map[string]FuncWebPluginInit
	mapWh     map[string]iris.Handler
	mapRoute  map[string]WebRoute

	//tracer *wrapperTrace.OtTracer
}

type WebRoute struct {
	Method string //多个方法使用空格分隔
	// method 为static 时， selector 表示 静态目录
	Selector string // 表示 服务名或静态目录
	// 表示服务名时， 服务名必须内部注册才有效
	Party string // 分组路由， 如果有， 实际URL 应该为/Party/Path
	Path  string // 路由地址
}

func newWebHandler() *WebCenter {
	wh := new(WebCenter)

	wh.app = iris.New()
	wh.app.Logger().SetLevel("info")

	wh.appBuild = false

	wh.mapPlugin = make(map[string]FuncWebPluginInit) // 插件map
	wh.mapWh = make(map[string]iris.Handler)          // 服务 与 处理函数之间map
	wh.mapRoute = make(map[string]WebRoute)           // 服务 与 http 路由 之间的map

	//w.app.HandleDir("/swagger", "./static/swagger")
	//
	return wh
}

//初始化设置, 执行各webPlugin的初始化函数
func (w *WebCenter) Init(cfg *config.ServiceConfig) {
	w.cfg = cfg
	//oap服务 的IP
	oapServer := ""
	if value, bExist := cfg.GetParam("oap.server"); bExist {
		oapServer = value
	}

	//oap 实例的服务名，默认与服务名相同
	serviceName := cfg.ServiceName
	if value, bExist := cfg.GetParam("oap.serviceName"); bExist {
		serviceName = value
	}

	//oap 实例的ID
	instanceId := ""
	if value, bExist := cfg.GetParam("oap.instance.id"); bExist {
		instanceId = value
	}

	if 0 < len(oapServer) {
		log.Info("create tracer", zap.String("oap.server", oapServer),
			zap.String("oap.serviceName", serviceName),
			zap.String("oap.instance.id", instanceId),
		)
		//w.tracer = wrapperTrace.TraceBoot(oapServer, serviceName, instanceId)
	}
	//添加默认路由
	w.SetHttpRoute("static", "", "/swagger", "./static/swagger")

	//执行各WebPlugin的初始化设置
	for _, plugin := range w.mapPlugin {
		plugin(w)
	}

	//设置路由
	for _, r := range cfg.Routes {
		w.SetHttpRoute(r.Method, r.Party, r.Path, r.Selector)
	}

}

//注册web插件
//注册服务对应的处理函数
func (w *WebCenter) RegisterWebPlugin(serviceName string, f FuncWebPluginInit) {
	//service全部转换为小写
	w.mapPlugin[strings.ToLower(serviceName)] = f
}

//注册服务对应的处理函数
func (w *WebCenter) RegisterWebHandler(serviceName string, h iris.Handler) {
	//service全部转换为小写
	w.mapWh[strings.ToLower(serviceName)] = h
}

//////设置静态目录
//func (w *WebCenter)SetHttpDir(route string , dir string) {
//	w.app.HandleDir(route, dir)
//}

//设置Http路由, method 为static 表示静态目录
//
func (w *WebCenter) SetHttpRoute(httpMethod string, party string, path string, service string) {
	sn := strings.ToLower(service)
	key := sn + "_" + httpMethod + "_" + path
	w.mapRoute[key] = WebRoute{
		Selector: sn,
		Method:   httpMethod,
		Path:     path,
		Party:    party,
	}
}

//临时测试接口
func (w *WebCenter) HandleDir(requestPath, directory string, opts ...iris.DirOptions) {
	w.app.HandleDir(requestPath, directory, opts...)
}

//该函数只能执行一次
func (w *WebCenter) GetHttpHandler() http.Handler {
	//设置实际http路由
	if !w.appBuild {
		w.appBuild = true
		//分组
		partyList := make(map[string]iris.Party)
		//循环添加路由
		//v4 := w.app.Party("")
		//v4.Use()
		for _, r := range w.mapRoute {
			var rp iris.Party
			if 0 < len(r.Party) {
				if pl, bExist := partyList[r.Party]; bExist {
					rp = pl
				} else {
					rp = w.app.Party(r.Party)
					rp.Use(w.before)
					rp.Done(w.after)
					partyList[r.Party] = rp
				}
			} else {
				rp = w.app
			}
			//log.Error("GetHttpHandler", zap.Reflect("r",r ), zap.Reflect("rp",rp ))
			if "static" == r.Method {
				rp.HandleDir(r.Path, r.Selector)
			} else {
				if h, ok := w.mapWh[r.Selector]; ok {
					rp.HandleMany(r.Method, r.Path, h)
				} else {
					//error

				}

			}
		}

		//app.SetExecutionRules(iris.ExecutionRules{
		//    Begin: iris.ExecutionOptions{Force: true},
		//    Main:  iris.ExecutionOptions{Force: true},
		//    Done:  iris.ExecutionOptions{Force: true},
		//})
		//app.Use(...)
		//app.Done(...)
		//w.app.UseGlobal(w.before)
		//w.app.DoneGlobal(w.after)
		w.app.Build()
	}
	rs := w.app.GetRoutes()
	for k, r := range rs {
		fmt.Println(k, r)
	}
	return w.app
}

//默认Client构建函数
func (w *WebCenter) NewClient() client.Client {
	//请求超时时间
	requestTimeout := 60 * time.Second
	if strValue, exist := w.cfg.GetParam("requestTimeout"); exist {
		if value, err := strconv.Atoi(strValue); nil == err {
			if 0 < value {
				requestTimeout = time.Duration(value) * time.Second
			}
		}
	}
	//错误重试次数
	retry := 3
	if strValue, exist := w.cfg.GetParam("retry"); exist {
		if value, err := strconv.Atoi(strValue); nil == err {
			if 0 < value {
				retry = value
			}
		}
	}

	opts := []client.Option{
		client.RequestTimeout(requestTimeout),
		client.Retries(retry),
	}

	//if nil != w.tracer{
	//	opts = append(opts, client.Wrap(wrapperTrace.NewClientWrapper(w.tracer)))
	//	//opts = append(opts, client.WrapCall(wrapperTrace.NewCallWrapper(w.tracer)))
	//}

	c := grpc.NewClient(opts...)
	//client.Wrap(wrapperTrace.NewClientWrapper(w.tracer)),
	//client.WrapCall(wrapperTrace.NewCallWrapper(w.tracer)),
	//)
	return c
}

//func SetCallOpt(opts ...client.CallOption){
//	for _,o := range opts{
//		callOpt = append(callOpt, o)
//	}
//}
//
//func GetCallOpt() []client.CallOption{
//	return callOpt
//}
func (w *WebCenter) before(ctx iris.Context) {
	//...
	req := ctx.RequestPath(true)
	log.Info("http before", zap.String("RequestPath(true)", req))
	ctx.Next()
}

func (w *WebCenter) after(ctx iris.Context) {
	//...
	ctx.Next()
}
